Skip to content

feat(telemetry): USDT probes for tracing spans end - #257

Merged
fisherdarling merged 2 commits into
cloudflare:mainfrom
jsitnicki:jakub/PERF-2835-span-with-probe
Aug 31, 2026
Merged

feat(telemetry): USDT probes for tracing spans end#257
fisherdarling merged 2 commits into
cloudflare:mainfrom
jsitnicki:jakub/PERF-2835-span-with-probe

Conversation

@jsitnicki

Copy link
Copy Markdown
Contributor

Problem

Code bases which use foundations are already instrumented with tracing spans, but there is no easy way to measure the duration of a specific span with a BPF-based tracer, like bpftrace or ebpf_exporter. One would have to craft custom uprobes at code offsets that shift with every build, and match span start/end events across await points and thread hops.

Solution

span_with_probe!("span::name") — a drop-in replacement for tracing::span("...") that additionally emits a per-span USDT probe at span end, span_end_<sanitized name>, receiving the span duration (ns) as an argument.

Key features:

  • Attaching is zero-cost for everything else: each call site gets a probe semaphore that tracers bump on attach; unattached spans don't even record a timestamp.
  • Works regardless of span sampling — probes fire with tracing disabled.
  • linux/x86_64 only; other platforms degrade to plain tracing::span. aarch64 support to follow.
  • Comes with a demo workload + bpftrace script, examples/span_with_probe, to show the intended use.

Comment thread foundations-macros/src/span_with_probe.rs Outdated
@jsitnicki
jsitnicki force-pushed the jakub/PERF-2835-span-with-probe branch from f84e8b1 to 7ec8942 Compare August 28, 2026 10:17
@jsitnicki

Copy link
Copy Markdown
Contributor Author

Per our discussion off-line, reworked the changes to support span_fn.

This called for a completely different approach than in span_with_probe! case.
Wrapping an existing span_fn macro with another macro (span_fn_with_probe?)
seemed silly. I've added a new option instead - end_probe. span_fn shares
what's possible with span_with_probe!.

Other changes:

Open question: Do we want to mark this as unstable and gate it be a crate
feature for now? How flexible are we on public API changes?

What's next? As a follow-up I will work on probe-rs to:

  1. Propose the public API change that would let us drop the asm! snippets in
    foundations.
  2. Add aarch64 support.
  3. Add optimized syscall-based USDT (nop,nop10 combo) probe support.

/// drops. Arming records the start timestamp unconditionally with respect
/// to sampling, so probes work even when span tracing is disabled.
#[doc(hidden)]
pub fn __arm_probe(&mut self, record_probe_start: bool, end_probe: fn(u64)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make this #[inline(always)] to avoid the function call in the common (disabled) case. same for DualSpanScope::__arm_probe.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should also just pull up the record_probe_start check into __arm_probe caller.

@TheJokr

TheJokr commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

LGTM other than that 1 nit!

@jsitnicki
jsitnicki force-pushed the jakub/PERF-2835-span-with-probe branch from 7ec8942 to e7ced1f Compare August 31, 2026 12:13
@jsitnicki

Copy link
Copy Markdown
Contributor Author
  • pull up check if probe is enabled out of __arm_probe
  • annotate __arm_probe with #[inline(always)]
  • update sample output in examples/README.md

…ption

Our code bases are already instrumented with tracing spans, but there is
no easy way to attach a BPF tracer to a specific span's start/end and
measure its duration: one would have to craft custom uprobes at specific
code offsets, which shift with every build, and then match span start and
end events to each other across await points and thread hops, since an
async span can be suspended and resumed on a different thread.

span_with_probe! (and its span_fn attribute counterpart, end_probe =
true) emit a per-span USDT probe named span_end__<sanitized span name>
which fires at span end with the span duration as an argument, so a
tracer can attach to a single span by name while all other spans pay no
cost. The probe is armed via a per-span semaphore only while a tracer is
attached and works regardless of span sampling.
Runs spans instrumented with span_with_probe! and span_fn's end_probe
option in a loop, with distinct delay ranges so their durations can be
told apart. Comes with a bpftrace script that attaches to the span end
probes and prints duration histograms.
@jsitnicki
jsitnicki force-pushed the jakub/PERF-2835-span-with-probe branch from e7ced1f to 1851dcc Compare August 31, 2026 13:01
@jsitnicki

Copy link
Copy Markdown
Contributor Author
  • Wrap SEC("usdt/<path>:<provider>:<name>") in backticks to make rustdoc happy

@fisherdarling
fisherdarling merged commit 410cc93 into cloudflare:main Aug 31, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants